﻿#ifndef _ICMPV4_H_
#define _ICMPV4_H_

/**
 * icmp 协议
 * 1.收到数据后检查和发送时是否一致
 * 2.当尝试连接目的计算机上某个不存在或者没有运行的应用程序时，会使用ICMP协议向请求方报告端口不可达的信息
 */

#include "net_err.h"
#include "ipaddr.h"
#include "pktbuf.h"

#define UNREACH_HDR_ORIGINAL_DATAGRAM 576 // 参考tcp/ip详解
#define UNREACH_HDR_UNUSED 4              // 包头中unused字段,参考rfc_792

// icmp包头中的type字段类型 参考rfc_792
typedef enum _icmp_type_t
{
    ICMPV4_ECHO_REQUEST = 8,
    ICMPV4_ECHO_REPLY = 0,
    ICMPV4_UNREACH = 3
} icmp_type_t;

// icmp包头中当type为unreach时,code字段取值 参考rfc_792
typedef enum _icmp_unreach_code_t
{
    ICMPV4_UNREACH_NET = 0,
    ICMPV4_UNREACH_HOST,
    ICMPV4_UNREACH_PROTOCOL,
    ICMPV4_UNREACH_PORT,
    ICMPV4_UNREACH_FRAG,
    ICMPV4_UNREACH_SRCROUTE
} icmp_unreach_code_t;

// icmp包头中的code类型
typedef enum _icmp_code_t
{
    ICMPV4_ECHO = 0
} icmp_code_t;

#pragma pack(1)

// icmpv4协议包头结构
typedef struct _icmpv4_hdr_t
{
    uint8_t type;      // 类型
    uint8_t code;      // 代码
    uint16_t checksum; // 校验和
    // 类型和代码的数据放在数据包格式中
} icmpv4_hdr_t;

typedef struct _icmpv4_pkt_t
{
    icmpv4_hdr_t hdr; // 包头
    union
    {
        uint32_t reverse; // 类型和代码中数据(保留)
    };
    uint8_t data[1]; // 数据包起始地址
} icmpv4_pkt_t;

#pragma pack()

net_err_t icmpv4_init();
net_err_t icmpv4_in(ipaddr_t *src_ip, ipaddr_t *netif_ip, pktbuf_t *buf);
net_err_t icmpv4_out(ipaddr_t *dest, ipaddr_t *src, pktbuf_t *buf);
net_err_t icmpv4_out_unreach(ipaddr_t *dest_ip, ipaddr_t *src_ip, uint8_t code, pktbuf_t *buf);

#endif